/*
 * Copyright (c) 1997, 1998, 2003, 2006 Aleksandar Samardzic
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <assert.h>		/* for assert() function */
#include <stdlib.h>		/* for calloc() function */
#include <string.h>		/* for strlen() function */
#include "image.h"
#include "ppm_image.h"

/* Image_Init - Image class constructor */
void
Image_Init(this, width, height)
     PImage         *this;
     DWord           width;
     DWord           height;
{
	/* set image width and height */
	this->width = width, this->height = height;

	/* allocate and initialize pixels */
	this->pPixels = calloc(this->width * this->height, sizeof(PColor));
	assert(this->pPixels != NULL);
}

/* Image_Clean - Image class destructor */
void
Image_Clean(this)
     PImage         *this;
{
	free(this->pPixels);
}

/* Image_SimpleBoxResample - resample image applying simple box filter */
void
Image_SimpleBoxResample(this)
     PImage         *this;
{
	PColor         *pPixel,
	               *pPixelE,
	               *pPixelN,
	               *pPixelNE;
	PColor         *pAAPixels,
	               *pAAPixel;
	DWord           row,
	                col;

	/* at least 2x2 pixel image is necessary in order to apply this
	 * filter */
	if (this->width <= 1 || this->height <= 1)
		return;

	/* new image has one row and one col less than original image */
	this->width--, this->height--;

	/* initialize pointers to pixels */
	pPixel = this->pPixels, pPixelE = pPixel + 1, pPixelN =
	    pPixel + (this->width + 1), pPixelNE = pPixelN + 1;

	/* allocate storage for new pixels */
	pAAPixel = pAAPixels =
	    malloc(this->width * this->height * sizeof(PColor));
	assert(pAAPixels != NULL);

	/* apply filter */
	for (row = 0; row < this->height; row++) {
		for (col = 0; col < this->width; col++, pAAPixel++) {
			/* new pixel is average of four pixels from
			 * previous image */
			(*pAAPixel)[RED] =
			    ((*pPixel)[RED] + (*pPixelE)[RED] +
			     (*pPixelN)[RED] + (*pPixelNE)[RED]) / 4;
			(*pAAPixel)[GREEN] =
			    ((*pPixel)[GREEN] + (*pPixelE)[GREEN] +
			     (*pPixelN)[GREEN] + (*pPixelNE)[GREEN]) / 4;
			(*pAAPixel)[BLUE] =
			    ((*pPixel)[BLUE] + (*pPixelE)[BLUE] +
			     (*pPixelN)[BLUE] + (*pPixelNE)[BLUE]) / 4;
			pPixel++, pPixelE++, pPixelN++, pPixelNE++;
		}
		pPixel++, pPixelE++, pPixelN++, pPixelNE++;
	}

	/* set new pixels */
	free(this->pPixels);
	this->pPixels = pAAPixels;
}

/* Image_Deserialize - write image to standard output */
Bool
Image_Deserialize(this, pComment)
     PImage         *this;
     char           *pComment;
{
	PColor         *pPixel;
	DWord           row,
	                col;
	PPMImage        ppmImage;
	Byte           *pPPMPixel;
	Bool            result;

	/* create PPM image */
	PPMImage_Init(&ppmImage, this->width, this->height, 255,
		      "Created by Tinos Ray Tracer.");

	/* convert pixels to PPM pixels */
	pPPMPixel = ppmImage.pPixels;
	for (row = 0; row < this->height; row++) {
		pPixel =
		    this->pPixels + (this->height - 1 - row) * this->width;
		for (col = 0; col < this->width; col++, pPixel++) {
			*(pPPMPixel++) = (Byte) (255 * (*pPixel)[RED]);
			*(pPPMPixel++) = (Byte) (255 * (*pPixel)[GREEN]);
			*(pPPMPixel++) = (Byte) (255 * (*pPixel)[BLUE]);
		}
	}

	/* write PPM image to standard output */
	result = (Bool) PPMImage_Deserialize(&ppmImage);

	/* destroy PPM image */
	PPMImage_Clean(&ppmImage);
	return result;
}
